//
//  BDMBaseOperationManagerLib3.m
//  welkin
//
//  Created by liyingpeng on 16/4/29.
//  Copyright © 2016年 com.baidu.cid. All rights reserved.
//

#import "BDMBaseOperationManager.h"
#import "AFNetworking.h"
#import "UIKit+AFNetworking.h"
#import "SDURLCache.h"
#import "BDMError.h"
#import "UIDevice+serialNumber.h"
#import <libkern/OSAtomic.h>

#define kCacheSizeMemory    4*1024*1024     // 4MB
#define kCacheSizeDisk      100*1024*1024   // 100MB

@interface BDMBaseOperationManager ()

@property(nonatomic, strong) NSMutableDictionary *dispatchTable;
@property(nonatomic, strong) NSMutableArray *groupRequestArray;

@property(nonatomic, strong) NSMutableArray *sessionManagerArray;

@end

@implementation BDMBaseOperationManager

#pragma mark - life circle

+ (instancetype)manager {
    return [[[self class] alloc] init];
}

- (instancetype)init {
    if (self = [super init]) {
        self.sessionManagerArray = [NSMutableArray array];
    }
    return self;
}

#pragma mark - public method

- (void)urlCacheInitialization
{
    SDURLCache *urlCache = [[SDURLCache alloc] initWithMemoryCapacity:kCacheSizeMemory
                                                         diskCapacity:kCacheSizeDisk
                                                             diskPath:nil];
    [NSURLCache setSharedURLCache:urlCache];
    
    [[AFNetworkActivityIndicatorManager sharedManager] setEnabled:YES];
}

- (void)clearAllURLCache
{
    [[NSURLCache sharedURLCache] removeAllCachedResponses];
}

- (AFHTTPSessionManager *)getSessionManagerByRequst:(BDMHTTPRequestModel *)requestModel {
    AFHTTPRequestSerializer *requestSerializer;
    AFHTTPResponseSerializer *responseSerializer;
    if ([requestModel.requestMethod isEqualToString:HTTP_REQUEST_POST]) {
        if (HTTP_REQUEST_TYPE_JSON == requestModel.requestType) {
            requestSerializer = [AFJSONRequestSerializer serializer];
        } else if (HTTP_REQUEST_TYPE_DATA_UCLOGIN == requestModel.requestType) {
            requestSerializer = [AFUCLoginRequestSerializer serializer];
        } else if (HTTP_REQUEST_TYPE_FORM == requestModel.requestType) {
            requestSerializer = [AFHTTPRequestSerializer serializer];
        }
    }
    else {
        requestSerializer = [AFJSONRequestSerializer serializer];
    }
    
    if (HTTP_RETURN_TYPE_JSON == requestModel.returnType) {
        responseSerializer = [AFJSONResponseSerializer serializer];
    } else if (HTTP_RETURN_TYPE_DATA == requestModel.returnType){
        responseSerializer = [AFHTTPResponseSerializer serializer];
    }
    
    AFHTTPSessionManager *aManager = nil;
    @synchronized (self) {
        for (AFHTTPSessionManager *manager in self.sessionManagerArray) {
            if (manager.requestSerializer.class == requestSerializer.class && manager.responseSerializer.class == responseSerializer.class) {
                aManager = manager;
                break;
            }
        }
        if (!aManager) {
            aManager = [AFHTTPSessionManager manager];
            aManager.requestSerializer = requestSerializer;
            aManager.responseSerializer = responseSerializer;
            [self.sessionManagerArray addObject:aManager];
        }
    }
    
    return aManager;
}

-(void)sendHttpRequestWithModel:(BDMHTTPRequestModel *) aRequestModel
                        success:(void (^)(id responseObject))aSuccessBlock
                        failure:(void (^)(BDMError *error))aFailureBlock
{
    //避免同一请求重复请求
    if ([BDMUtility isStringValidated:aRequestModel.identifier] && [self.dispatchTable objectForKey:aRequestModel.identifier] ) {
        return;
    }
    
    if (self.configRequestModelBlock) {
        aRequestModel = self.configRequestModelBlock(aRequestModel);
    }
    
    AFHTTPSessionManager *manager = [self getSessionManagerByRequst:aRequestModel];
    // 通过https的所有请求,因https请求需要证书
    manager.securityPolicy.allowInvalidCertificates = !aRequestModel.isUseSSL;
    
    id parameters = aRequestModel.paraDict;
    
    if ([aRequestModel.requestMethod isEqualToString:HTTP_REQUEST_POST]) {
        if (HTTP_REQUEST_TYPE_JSON == aRequestModel.requestType) {
            parameters = aRequestModel.postDict;
        } else if (HTTP_REQUEST_TYPE_DATA_UCLOGIN == aRequestModel.requestType) {
            parameters = [aRequestModel.postDict objectForKey:HTTP_REQUEST_POST];
        } else if (HTTP_REQUEST_TYPE_FORM == aRequestModel.requestType) {
            parameters = aRequestModel.postDict;
        }
    }
    
    NSURLSessionDataTask *dataTask = [self dataTaskWithSessionManager:manager HTTPMethod:aRequestModel.requestMethod URLString:aRequestModel.requestUrl customerHeader:aRequestModel.customHeader paraDic:aRequestModel.paraDict parameters:parameters cachePolicy:aRequestModel.cachePolicy success:^(NSURLSessionDataTask *dataTask, id responseObject) {
        //删除网络请求
        if ([BDMUtility isStringValidated:aRequestModel.identifier]) {
            [self.dispatchTable removeObjectForKey:aRequestModel.identifier];
        }
        
        if (aSuccessBlock) {
            aSuccessBlock(responseObject);
        }
    } failure:^(NSURLSessionDataTask *dataTask, NSError *error) {
        //删除网络请求
        if ([BDMUtility isStringValidated:aRequestModel.identifier]) {
            [self.dispatchTable removeObjectForKey:aRequestModel.identifier];
        }
        
        if (aFailureBlock) {
            aFailureBlock([BDMError errorWithError:error]);
        }
    }];
    
    //记录每次的网络请求
    if ([BDMUtility isStringValidated:aRequestModel.identifier]) {
        [self.dispatchTable setObject:dataTask forKey:aRequestModel.identifier];
    }
}

- (void)sendHttpRequestGroupWithModelArray:(NSArray<BDMHTTPRequestModel *> *)modelArray
                                  progress:(void(^)(id responseObject, NSString *identifier, BDMError *error))progress
                                  complete:(void(^)(BOOL isRequestSuccess))complete
                          isResultRestrict:(BOOL)isResultRestrict {
    
    __block int32_t value = 0;
    for (BDMHTTPRequestModel *aRequestModel in modelArray) {
        [self.groupRequestArray addObject:aRequestModel.identifier];
        
        //避免同一请求重复请求
        if ([BDMUtility isStringValidated:aRequestModel.identifier] && [self.dispatchTable objectForKey:aRequestModel.identifier] ) {
            return;
        }
        
        AFHTTPSessionManager *manager = [self getSessionManagerByRequst:aRequestModel];
        // 通过https的所有请求,因https请求需要证书
        manager.securityPolicy.allowInvalidCertificates = !aRequestModel.isUseSSL;
        
        id parameters = aRequestModel.paraDict;
        
        if ([aRequestModel.requestMethod isEqualToString:HTTP_REQUEST_POST]) {
            if (HTTP_REQUEST_TYPE_JSON == aRequestModel.requestType) {
                parameters = aRequestModel.postDict;
            } else if (HTTP_REQUEST_TYPE_DATA_UCLOGIN == aRequestModel.requestType) {
                parameters = [aRequestModel.postDict objectForKey:HTTP_REQUEST_POST];
            } else if (HTTP_REQUEST_TYPE_FORM == aRequestModel.requestType) {
                parameters = aRequestModel.postDict;
            }
        }
        
        BlockWeakObject(self, wself);
        NSURLSessionDataTask *dataTask = [self dataTaskWithSessionManager:manager HTTPMethod:aRequestModel.requestMethod URLString:aRequestModel.requestUrl customerHeader:aRequestModel.customHeader paraDic:aRequestModel.paraDict parameters:parameters cachePolicy:aRequestModel.cachePolicy success:^(NSURLSessionDataTask *dataTask, id responseObject) {
            BlockStrongObject(wself, self);
            //删除网络请求
            if ([BDMUtility isStringValidated:aRequestModel.identifier]) {
                [self.dispatchTable removeObjectForKey:aRequestModel.identifier];
            }
            if (progress) {
                progress(responseObject, aRequestModel.identifier, nil);
            }
            OSAtomicIncrement32(&value);
            if (value >= modelArray.count) {
                if (complete) {
                    complete(YES);
                }
            }
        } failure:^(NSURLSessionDataTask *dataTask, NSError *error) {
            BlockStrongObject(wself, self);
            //删除网络请求
            if ([BDMUtility isStringValidated:aRequestModel.identifier]) {
                [self.dispatchTable removeObjectForKey:aRequestModel.identifier];
            }
            if (progress) {
                progress(nil, aRequestModel.identifier, [BDMError errorWithError:error]);
            }
            OSAtomicIncrement32(&value);
            if (value >= modelArray.count) {
                if (complete) {
                    if (isResultRestrict) {
                        complete(NO);
                    }
                    else {
                        complete(YES);
                    }
                }
            }
            if (isResultRestrict) {
                // 取消剩余请求，并完成回调
                // 否则，一个出现错误记录即可 不需要终止其余请求
                [self cancelRequestForIdentifierList:self.groupRequestArray];
                if (complete) {
                    complete(NO);
                }
            }
        }];
        
        //记录每次的网络请求
        if ([BDMUtility isStringValidated:aRequestModel.identifier]) {
            [self.dispatchTable setObject:dataTask forKey:aRequestModel.identifier];
        }
    }
}

- (void)uploadFileWithFileModel:(BDMUploadFileModel *)aUploadFileModel
               progressCallBack:(void (^)(NSUInteger __unused bytesWritten,
                                          long long totalBytesWritten,
                                          long long totalBytesExpectedToWrite))progressBlock
                        success:(void (^)(id responseObject))aSuccessBlock
                        failure:(void (^)(NSError *error))aFailureBlock
{
    //避免同一请求重复请求
    if ([BDMUtility isStringValidated:aUploadFileModel.identifier] && [self.dispatchTable objectForKey:aUploadFileModel.identifier] ) {
        return;
    }
    
    AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
    
    if (HTTP_RETURN_TYPE_JSON == aUploadFileModel.returnType) {
        manager.responseSerializer = [AFJSONResponseSerializer serializer];
    } else if (HTTP_RETURN_TYPE_DATA == aUploadFileModel.returnType){
        manager.responseSerializer = [AFHTTPResponseSerializer serializer];
    }

    NSError *error = nil;
    NSMutableURLRequest *request = [[AFHTTPRequestSerializer serializer] multipartFormRequestWithMethod:@"POST" URLString:aUploadFileModel.requestUrl parameters:aUploadFileModel.requestParaDict constructingBodyWithBlock:^(id<AFMultipartFormData> formData) {
        if (aUploadFileModel) {
            switch (aUploadFileModel.uploadFileType) {
                case BDMUploadFileType_Data:
                {
                    [formData appendPartWithFileData:aUploadFileModel.fileData name:aUploadFileModel.name fileName:aUploadFileModel.fileName mimeType:aUploadFileModel.mimeType];
                    break;
                }
                case BDMUploadFileType_FileURL:
                {
                    [formData appendPartWithFileURL:aUploadFileModel.filePathURL name:aUploadFileModel.name fileName:aUploadFileModel.fileName mimeType:aUploadFileModel.mimeType error:nil];
                    break;
                }
                case BDMUploadFileType_InputStream:
                    break;
            }
        }
    } error:&error];
    
    NSURLSessionUploadTask *uploadTask = [manager uploadTaskWithStreamedRequest:request progress:^(NSProgress * _Nonnull uploadProgress) {
        progressBlock((NSInteger)uploadProgress.completedUnitCount, (long long)uploadProgress.completedUnitCount, (long long)uploadProgress.totalUnitCount);
    } completionHandler:^(NSURLResponse * _Nonnull response, id  _Nullable responseObject, NSError * _Nullable error) {
        if ([BDMUtility isStringValidated:aUploadFileModel.identifier]) {
            [self.dispatchTable removeObjectForKey:aUploadFileModel.identifier];
        }
        if (error) {
            if (aFailureBlock) {
                dispatch_async(dispatch_get_main_queue(), ^{
                    aFailureBlock(error);
                });
            }
        }
        else {
            if (aSuccessBlock) {
                dispatch_async(dispatch_get_main_queue(), ^{
                    aSuccessBlock(responseObject);
                });
            }
        }
    }];

    if ([BDMUtility isStringValidated:aUploadFileModel.identifier]) {
        [self.dispatchTable setObject:uploadTask forKey:aUploadFileModel.identifier];
    }

    [uploadTask resume];
}

- (void)downloadFileWithFileModel:(BDMDownloadFileModel *)aDownloadModel
                 progressCallBack:(void (^)(NSUInteger bytesRead,
                                            long long totalBytesRead,
                                            long long totalBytesExpectedToRead))progressBlock
                          success:(void (^)(id responseObject))aSuccessBlock
                          failure:(void (^)(NSError *error))aFailureBlock
{
    //避免同一请求重复请求
    if ([BDMUtility isStringValidated:aDownloadModel.identifier] && [self.dispatchTable objectForKey:aDownloadModel.identifier] ) {
        return;
    }
    
    NSError *error = nil;
    NSMutableURLRequest *request = [[AFHTTPRequestSerializer serializer] requestWithMethod:@"GET" URLString:aDownloadModel.downloadURL parameters:aDownloadModel.downloadParaDict error:&error];
    
    NSString *downloadFilePath = nil;
    if ([aDownloadModel .downloadPath respondsToSelector:@selector(containsString:)]) {
        if (![aDownloadModel.downloadPath containsString:aDownloadModel.fileName]) {
            downloadFilePath = [NSString stringWithFormat:@"%@/%@",aDownloadModel.downloadPath,aDownloadModel.fileName];
        } else {
            downloadFilePath = aDownloadModel.downloadPath;
        }
    } else {
        NSRange foundObj = [aDownloadModel.downloadPath rangeOfString:aDownloadModel.fileName options:NSCaseInsensitiveSearch];
        if (foundObj.length ==0) {
            downloadFilePath = [NSString stringWithFormat:@"%@/%@",aDownloadModel.downloadPath,aDownloadModel.fileName];
        } else {
            downloadFilePath = aDownloadModel.downloadPath;
        }
    }
    
    //检查文件是否已经下载了一部分
    unsigned long long downloadedBytes = 0;
    if (!aDownloadModel.resumeDownload) {
        if ([[NSFileManager defaultManager] fileExistsAtPath:downloadFilePath]) {
            //获取已下载的文件长度
            downloadedBytes = [self fileSizeForPath:downloadFilePath];
            if (downloadedBytes > 0) {
                NSMutableURLRequest *mutableURLRequest = [request mutableCopy];
                NSString *requestRange = [NSString stringWithFormat:@"bytes=%llu-", downloadedBytes];
                [mutableURLRequest setValue:requestRange forHTTPHeaderField:@"Range"];
                request = mutableURLRequest;
            }
        }
    }
    //不使用缓存，避免断点续传出现问题
    [[NSURLCache sharedURLCache] removeCachedResponseForRequest:request];
    
    AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
    
    if (aDownloadModel.SSL) {
        manager.securityPolicy = [self customSecurityPolicy:aDownloadModel.certificateName];
    }
    
    [manager setSessionDidReceiveAuthenticationChallengeBlock:^NSURLSessionAuthChallengeDisposition (NSURLSession *session, NSURLAuthenticationChallenge *challenge, NSURLCredential * __autoreleasing *credential) {
        return NSURLSessionAuthChallengePerformDefaultHandling;
    }];
    
    //下载请求
    
    NSURLSessionDownloadTask *downloadTask = [manager downloadTaskWithRequest:request progress:^(NSProgress * _Nonnull downloadProgress) {
        //
    } destination:^NSURL * _Nonnull(NSURL * _Nonnull targetPath, NSURLResponse * _Nonnull response) {
        return [NSURL fileURLWithPath:downloadFilePath];
    } completionHandler:^(NSURLResponse * _Nonnull response, NSURL * _Nullable filePath, NSError * _Nullable error) {
        if ([BDMUtility isStringValidated:aDownloadModel.identifier]) {
            [self.dispatchTable removeObjectForKey:aDownloadModel.identifier];
        }
        if (error) {
            if (aFailureBlock) {
                dispatch_async(dispatch_get_main_queue(), ^{
                    aFailureBlock(error);
                });
            }
        }
        else {
            if (aSuccessBlock) {
                dispatch_async(dispatch_get_main_queue(), ^{
                    aSuccessBlock(response);
                });
            }
        }
    }];
    
    void (^downloadDidWriteBlock)(NSURLSession * _Nonnull session, NSURLSessionDownloadTask * _Nonnull downloadTask, int64_t bytesWritten, int64_t totalBytesWritten, int64_t totalBytesExpectedToWrite) = ^(NSURLSession * _Nonnull session, NSURLSessionDownloadTask * _Nonnull downloadTask, int64_t bytesWritten, int64_t totalBytesWritten, int64_t totalBytesExpectedToWrite) {
        if (progressBlock) {
            dispatch_async(dispatch_get_main_queue(), ^{
                progressBlock((NSUInteger)bytesWritten, totalBytesWritten, totalBytesExpectedToWrite);
            });
        }
    };
    
    [manager setDownloadTaskDidWriteDataBlock:downloadDidWriteBlock];
    
    if ([BDMUtility isStringValidated:aDownloadModel.identifier]) {
        [self.dispatchTable setObject:downloadTask forKey:aDownloadModel.identifier];
    }
    
    [downloadTask resume];
}

- (void)cancelRequestForIdentifier:(NSString *)requestID
{
    NSURLSessionDataTask *dataTask = self.dispatchTable[requestID];
    [dataTask cancel];
    [self.dispatchTable removeObjectForKey:requestID];
}

- (void)cancelRequestForIdentifierList:(NSMutableArray *)requestIDList
{
    for (NSString *requestId in requestIDList) {
        [self cancelRequestForIdentifier:requestId];
    }
}

- (void)cancelAllRequest {
    for (NSURLSessionDataTask *dataTask in [self.dispatchTable allValues]) {
        [dataTask cancel];
    }
}

#pragma mark - private method

- (NSURLSessionDataTask *)dataTaskWithSessionManager:(AFHTTPSessionManager *)manager
                                          HTTPMethod:(NSString *)aRequestMethod
                                       URLString:(NSString *)URLString
                                  customerHeader: (NSDictionary *)aCustomerHeader
                                         paraDic:(id)aParaDic parameters:(id)aParameters
                                     cachePolicy:(NSURLRequestCachePolicy)aPolicy
                                         success:(void (^)(NSURLSessionDataTask *dataTask, id responseObject))success
                                         failure:(void (^)(NSURLSessionDataTask *dataTask, NSError *error))failure {
    NSMutableDictionary *paraDict = [[NSMutableDictionary alloc] initWithDictionary:aParaDic];
    
    NSMutableURLRequest *request;
    if ([aRequestMethod isEqualToString:HTTP_REQUEST_POST]) {
        NSMutableString * url = [[NSMutableString alloc] initWithString:URLString];
        if ([paraDict count] != 0) {
            [url appendString:@"?"];
            [paraDict enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
                [url appendFormat:@"%@=%@&",key, [BDMUtility urlEncoded:obj] ];
            }];
        }
        request = [manager.requestSerializer requestWithMethod:aRequestMethod URLString:[[NSURL URLWithString:url relativeToURL:manager.baseURL] absoluteString] parameters:aParameters error:nil];
    } else {
        request = [manager.requestSerializer requestWithMethod:aRequestMethod URLString:[[NSURL URLWithString:URLString relativeToURL:manager.baseURL] absoluteString] parameters:paraDict error:nil];
    }
    
    request.cachePolicy = aPolicy;
    
    // aParameters为dic类型才添加
    if ([aParameters isKindOfClass:[NSDictionary class]] || [aParameters isKindOfClass:[NSMutableDictionary class]]) {
        [paraDict addEntriesFromDictionary:aParameters];
    }
    
    // 按照app需求配置响应参数
    if (self.configHeaderBlock) {
        self.configHeaderBlock(request, paraDict, aCustomerHeader);
    }
    else {
        [self addHeaderForRequest:request customerHeader:aCustomerHeader];
    }
    
    __block NSURLSessionDataTask *dataTask = nil;

    dataTask = [self dataTaskWithSessionManager:manager Request:request completionHandler:^(NSURLResponse * _Nonnull response, id _Nullable responseObject, NSError * _Nullable error) {
        if (error) {
            if (failure) {
                failure(dataTask, error);
            }
        }
        else {
            if (success) {
                success(dataTask, responseObject);
            }
        }
    }];
    
    // 添加重定向处理
    [self setRedirectHandleWithSessionManager:manager];
    
    // 添加缓存策略
    BlockWeakObject(manager, wManager);
    [manager setDataTaskWillCacheResponseBlock:^NSCachedURLResponse * _Nonnull(NSURLSession * _Nonnull session, NSURLSessionDataTask * _Nonnull dataTask, NSCachedURLResponse * _Nonnull proposedResponse) {
        BlockStrongObject(wManager, manager);
        if (self.configAdoptCachePolicyBlock) {
            BOOL isJsonValid = [manager.responseSerializer isKindOfClass:[[AFJSONResponseSerializer serializer] class]];
            return self.configAdoptCachePolicyBlock(request, proposedResponse, isJsonValid);
        }
        return nil;
    }];
    
    [dataTask resume];
    
    return dataTask;
}


- (NSURLSessionDataTask *)dataTaskWithSessionManager:(AFHTTPSessionManager *)manager
                                             Request:(NSURLRequest *)request
                            completionHandler:(void (^)(NSURLResponse * _Nonnull, id _Nullable, NSError * _Nullable))completionHandler {
    
    BlockWeakObject(self, wself);
    BlockWeakObject(manager, wManager);
    void (^completeBlock)(NSURLResponse *response, id _Nullable responseObject,  NSError * _Nullable error) = ^(NSURLResponse *response, id _Nullable responseObject,  NSError * _Nullable error) {
        BlockStrongObject(wself, self);
        BlockStrongObject(wManager, manager);
        // 根据业务需求处理成功回调后的状态码
        if (self.configResultHandlerBlock) {
            NSInteger statusCode = [(NSHTTPURLResponse *)response statusCode];
            BOOL isJsonValid = [manager.responseSerializer isKindOfClass:[[AFJSONResponseSerializer serializer] class]];
            error =  self.configResultHandlerBlock(responseObject, isJsonValid, statusCode);
        }
        completionHandler(response, responseObject, error);
    };
    
    return [manager dataTaskWithRequest:request completionHandler:completeBlock];
}

/**
 *  @brief  增加ssl验证
 *
 *  @return 安全策略对象
 */
- (AFSecurityPolicy*)customSecurityPolicy:(NSString *)certificateName
{
    /**** SSL Pinning ****/
    NSString *cerPath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:certificateName];
    NSData *certData = [NSData dataWithContentsOfFile:cerPath];
    AFSecurityPolicy *securityPolicy = [[AFSecurityPolicy alloc] init];
    [securityPolicy setAllowInvalidCertificates:YES];
    [securityPolicy setPinnedCertificates:[NSSet setWithObjects:certData, nil]];
    
    /**** SSL Pinning ****/
    
    return securityPolicy;
}

/*!
 *  添加重定向处理
 */
- (void)setRedirectHandleWithSessionManager:(AFHTTPSessionManager *)sessionManager {
    [sessionManager setTaskWillPerformHTTPRedirectionBlock:^NSURLRequest * _Nonnull(NSURLSession * _Nonnull session, NSURLSessionTask * _Nonnull task, NSURLResponse * _Nonnull response, NSURLRequest * _Nonnull request) {
        /*
         *  redirectResponse 是包含了重定向之前的request的信息
         *  302是重定向
         */
        if (response) {
            return nil;
        } else {
            return request;
        }
    }];
}

- (void)addHeaderForRequest:(NSMutableURLRequest *)aRequest
             customerHeader:(NSDictionary *)aCustomerHeader
{
    if ([aCustomerHeader count] != 0) {
        [aCustomerHeader enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
            [aRequest setValue:obj forHTTPHeaderField:key];
        }];
    }
}

/**
 *  @brief  获取已下载的文件大小
 *
 *  @param path 文件路径
 *
 *  @return 文件大小
 */
- (unsigned long long)fileSizeForPath:(NSString *)path {
    signed long long fileSize = 0;
    NSFileManager *fileManager = [NSFileManager new];
    if ([fileManager fileExistsAtPath:path]) {
        NSError *error = nil;
        NSDictionary *fileDict = [fileManager attributesOfItemAtPath:path error:&error];
        if (!error && fileDict) {
            fileSize = [fileDict fileSize];
        }
    }
    return fileSize;
}

#pragma mark - getters

- (NSMutableDictionary *)dispatchTable
{
    if (_dispatchTable == nil) {
        _dispatchTable = [[NSMutableDictionary alloc] init];
    }
    return _dispatchTable;
}

- (NSMutableArray *)groupRequestArray {
    if (!_groupRequestArray) {
        _groupRequestArray = [[NSMutableArray alloc] init];
    }
    return _groupRequestArray;
}

@end
